package com.example.oauth2authserver.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.example.oauth2authserver.model.OAuthClientDetail;
import com.example.oauth2authserver.service.IOAuthClientDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class MyClientDetailsService implements ClientDetailsService {
    @Autowired
    private IOAuthClientDetailService oAuthClientDetailService;
    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        BaseClientDetails clientDetails = null;
        try {
            OAuthClientDetail clientDetail = oAuthClientDetailService.findByClientId(clientId);
            clientDetails = new BaseClientDetails();
            clientDetails.setClientId(clientDetail.getClientId());

            List<String> resourceIds = new ArrayList<>();
            if (StringUtils.hasText(clientDetail.getResourceIds())) {
                resourceIds = Arrays.stream(clientDetail.getResourceIds().split(",")).collect(Collectors.toList());
            }
            clientDetails.setResourceIds(resourceIds);

            List<String> grantTypes = new ArrayList<>();
            if (StringUtils.hasText(clientDetail.getAuthorizedGrantTypes())) {
                grantTypes = Arrays.stream(clientDetail.getAuthorizedGrantTypes().split(",")).collect(Collectors.toList());
            }
            clientDetails.setAuthorizedGrantTypes(grantTypes);

            List<String> scopes = new ArrayList<>();
            if (StringUtils.hasText(clientDetail.getScope())) {
                scopes = Arrays.stream(clientDetail.getScope().split(",")).collect(Collectors.toList());
            }
            clientDetails.setScope(scopes);

            List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
            if (StringUtils.hasText(clientDetail.getAuthorities())) {
                List<String> authorities = Arrays.stream(clientDetail.getAuthorities().split(",")).collect(Collectors.toList());
                grantedAuthorities = authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
            }
            clientDetails.setAuthorities(grantedAuthorities);

            clientDetails.setClientSecret(clientDetail.getClientSecret());

            Set<String> autoApproveScopes = new HashSet<>();
            if (StringUtils.hasText(clientDetail.getAutoApprove())) {
                autoApproveScopes = StringUtils.commaDelimitedListToSet(clientDetail.getAutoApprove());
            }
            clientDetails.setAutoApproveScopes(autoApproveScopes);
            clientDetails.setAccessTokenValiditySeconds(clientDetail.getAccessTokenValidity());
            clientDetails.setRefreshTokenValiditySeconds(clientDetail.getRefreshTokenValidity());

            Set<String> redirectUriSet = new HashSet<>();
            if (StringUtils.hasText(clientDetail.getWebServerRedirectUri())) {
                redirectUriSet = StringUtils.commaDelimitedListToSet(clientDetail.getWebServerRedirectUri());
            }
            clientDetails.setRegisteredRedirectUri(redirectUriSet);
            if (StringUtils.hasText(clientDetail.getAdditionalInformation())) {
                Map<String,Object> additionalInformation = JSONObject.parseObject(clientDetail.getAdditionalInformation(),Map.class);
                clientDetails.setAdditionalInformation(additionalInformation);
            }
        } catch (EmptyResultDataAccessException e) {
            throw new NoSuchClientException("No Client With requested id: " + clientId);
        }
        return clientDetails;
    }
}
